package top.lingkang.finalvalidated.core;

import top.lingkang.finalvalidated.error.CheckException;
import top.lingkang.finalvalidated.handle.CustomValidHandle;
import top.lingkang.finalvalidated.handle.NestingValidHandle;
import top.lingkang.finalvalidated.handle.ValidHandle;
import top.lingkang.finalvalidated.handle.ValidVal;
import top.lingkang.finalvalidated.utils.FinalValidatorUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lingkang
 * created by 2024/1/26
 */
public class FinalValidatorFactory {
    // 用于缓存该类是否需要校验
    private static final Map<Class<?>, CheckObject> cache = new ConcurrentHashMap<>();
    /**
     * 如果有国际化需要，可以继承 Properties 重写获取key方案
     * <pre>{@code
     * // 重新设置消息处理
     * FinalValidatorFactory.message = new MyProperties();
     * }</pre>
     */
    public static Properties message = new Properties();

    public boolean supports(Class<?> clazz) {
        CheckObject check = cache.get(clazz);
        if (check != null)
            return check.isNeed();

        check = new CheckObject();
        if (clazz != null) {
            // 判断是否需要校验入参对象
            if (FinalValidatorUtils.isNeedValid(clazz)) {
                // 需要校验并初始化校验
                check.setNeed(true);
                check.setHandles(initValidHandle(clazz));
            }
        }
        if (!FinalValidator.isDev()) {
            cache.put(clazz, check);
        }
        return check.isNeed();
    }

    public void validate(Object target) {
        CheckObject checkObject = cache.get(target.getClass());
        for (ValidHandle handle : checkObject.getHandles()) {
            handle.valid(target);
        }
    }

    public void validate(Object target, Class<?>[] groups) {
        CheckObject checkObject = cache.get(target.getClass());
        for (ValidHandle handle : checkObject.getHandles()) {
            if (handle.getGroups().length != 0) {
                for (Class<?> group : groups) {
                    if (hasGroup(group, handle.getGroups())) {
                        handle.valid(target);
                        break;
                    }
                }
            } else {
                // 无 groups
                handle.valid(target);
            }
        }
    }

    /**
     * 添加自定义注解和处理
     *
     * @param annotation  自定义的注解
     * @param validHandle 自定义注解的校验处理
     */
    public void addCustom(Class<? extends Annotation> annotation, Class<? extends CustomValidHandle> validHandle) {
        FinalValidatorUtils.addCustom(annotation, validHandle);
    }

    public List<ValidHandle> getValidHandles(Class<?> clazz) {
        CheckObject checkObject = cache.get(clazz);
        return checkObject.getHandles();
    }

    private boolean hasGroup(Class<?> clazz, Class<?>[] groups) {
        for (Class<?> group : groups) {
            if (clazz == group) return true;
        }
        return false;
    }

    private synchronized List<ValidHandle> initValidHandle(Class<?> clazz) {
        List<ValidHandle> list = new ArrayList<>();
        List<Field> fieldList = FinalValidatorUtils.getAllFields(clazz);
        final List<Class<?>> currentNestingClass = new ArrayList<>();// 记录类型，防止无限套娃
        for (Field field : fieldList) {
            // 判断是否是对象嵌套对象
            if (field.getType() != clazz && !currentNestingClass.contains(field.getType())) {
                if (field.isAnnotationPresent(ValidObject.class)) {
                    // 嵌套属性时，只有在嵌套属性上添加 @ValidObject 注解才会校验
                    currentNestingClass.add(field.getType());// 防止无限套娃
                    List<Field> checkField = FinalValidatorUtils.getAllCheckField(field.getType());
                    if (!checkField.isEmpty()) {// 嵌套对象中，存在属性才会加入校验
                        // field.setAccessible(true); // 自从2.4.0起，弃用反射取值，改用getter取值
                        ValidVal validVal = FinalValidatorUtils.getValidVal(field, null, null);
                        list.add(new NestingValidHandle(initValidHandle(field.getType()), validVal));
                        continue;
                    }
                }
            }

            List<Annotation> validAnn = FinalValidatorUtils.getValidAnn(field);
            if (validAnn.isEmpty())
                continue;
            for (Annotation annotation : validAnn) {
                try {
                    list.add(FinalValidatorUtils.annotationToValidHandle(field, null, annotation));
                } catch (CheckException e) {
                    throw new CheckException("校验异常对象：" + clazz.getName(), e);
                }
            }
        }
        return list;
    }

    /**
     * 清理缓存，注意：清理后，您添加的自定义注解也被清除，需要重新添加。
     *
     * @since 2.3.0
     */
    public void clearCache() {
        cache.clear();
        FinalValidatorUtils.clearCache();
    }
}
